package com.gitee.huxing.course.config;

import com.gitee.huxing.course.annoation.CustomAutoConfig;
import com.gitee.huxing.course.util.SpringBeanContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Import;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.time.LocalDateTime;

/**
 * DependsOn是代表依赖某个类加载完成以后，当前类才继续加载
 * Import只是代表加载该类的同时，也要要求spring bean容器加载需要引入的类，没有顺序
 * @Description: 自动注入bean
 * @ProjectName: JavaCourse
 * @Package: com.gitee.huxing.core.config
 * @ClassName: DefinitionRegistryPostProcessor
 * @Author: huxing
 * @DateTime: 2021-09-05 上午12:04
 */
@Slf4j
@DependsOn("springBeanContext")
@Configuration
public class DefinitionRegistryBean {

    /** 基础包路径 **/
    private final String BASE_PACKAGE = "com.gitee.huxing";

    /** 资源路径名 **/
    private final String RESOURCE_PATTERN = "/**/*.class";

    /**
     * @Description: 扫描当前包下的所有class
     * @Author: huxing
     * @Date: 2021/9/5 上午12:08
     **/
    @PostConstruct
    public void scan(){
        log.info("开始自动装配相关的类: {}", LocalDateTime.now());
        //spring工具类，可以获取指定路径下的全部类
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        try {
            String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                    ClassUtils.convertClassNameToResourcePath(BASE_PACKAGE) + RESOURCE_PATTERN;
            Resource[] resources = resourcePatternResolver.getResources(pattern);
            //MetadataReader 的工厂类
            MetadataReaderFactory readerfactory = new CachingMetadataReaderFactory(resourcePatternResolver);
            for (Resource resource : resources) {
                //用于读取类信息
                MetadataReader reader = readerfactory.getMetadataReader(resource);
                //扫描到的class
                String classname = reader.getClassMetadata().getClassName();
                Class<?> clazz = Class.forName(classname);
                log.info("扫描到的注解类: {}", classname);
                //判断是否有指定主解
                CustomAutoConfig anno = clazz.getAnnotation(CustomAutoConfig.class);
                if (anno != null) {
                    //将注解中的类型值作为key，对应的类作为 value
                    String value = anno.value();
                    if (StringUtils.isEmpty(value)){
                        registerBean(classname, clazz);
                    } else {
                        registerBean(value, clazz);
                    }
                }
            }
        } catch (IOException | ClassNotFoundException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * @Description: 注册到bean容器中
     * @Author: huxing
     * @param name
     * @param beanClass
     * @Date: 2021/9/5 上午12:11
     **/
    private void registerBean(String name, Class<?> beanClass) {
        // 获取一个配置工厂
        ConfigurableApplicationContext context = (ConfigurableApplicationContext) SpringBeanContext.getApplicationContext();
        if (context == null){
            log.info("没有加载到bean工厂: {}", LocalDateTime.now());
        } else {
            // 获取bean的配置工厂
            DefaultListableBeanFactory factory = (DefaultListableBeanFactory)context.getBeanFactory();
            // 创建bean
            BeanDefinitionBuilder bean = BeanDefinitionBuilder.genericBeanDefinition(beanClass);
            // 注册到bean中
            factory.registerBeanDefinition(name, bean.getBeanDefinition());
        }
    }
}
